package com.linyubing.dao;
import com.linyubing.pojo.BasePojo;
import com.linyubing.utils.JDBCUtil;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
//泛型dao接口实现类：实现crud的模板方法
public class BaseDaoImpl<T extends BasePojo> implements BaseDao<T> {
    //存储实体类的Class对象
    private final Class<T> myClass;
    //构造函数
    public BaseDaoImpl(Class<T> myClass) {
        this.myClass=myClass;
    }
    //添加实体 insert into student (stuName,stuSex) values(?,?);
    @Override
    public boolean add(T entity) throws SQLException, InvocationTargetException, IllegalAccessException {
        String pojoName = myClass.getSimpleName(); // 获取纯类名，而不是全路径名
        String tableName = pojoName.toLowerCase();//类名全部小写是表名
        StringBuilder builder = new StringBuilder();
        StringBuilder builder2 = new StringBuilder();
        builder.append("insert into "+tableName+" ( ");
        builder2.append(" values ").append(" ( ");
        //获取所有的getXXX方法
        List<Method> methods = getAllGetXXX();
        for(int i=0;i<methods.size();i++) {
            //根据方法名获取字段名
            String filedName = getFieldByMethodName(methods.get(i).getName());
            //判断字段名是否以Id结尾
            if (filedName.endsWith("Id")) {
                continue;
            } else {
                //拼接sql
                builder.append(filedName).append(",");
                builder2.append("?").append(",");
            }
        }
        //最后一个字符,替换为）
        builder.setCharAt(builder.length()-1,')');
        builder2.setCharAt(builder2.length()-1,')');
        String sql=builder.append(builder2).toString();
        //获取连接对象
        Connection connection = JDBCUtil.getConnection();
        //获取sql对象
        PreparedStatement stmt= JDBCUtil.getStatement(connection, sql);
        int count=1;
        for(int i=0;i<methods.size();i++){
            //根据方法名获取字段名
            String filedName=getFieldByMethodName(methods.get(i).getName());
            //判断字段名是否以Id结尾
            if(filedName.endsWith("Id")){
                continue;
            }else{
                //调用方法获取值
                Object value = methods.get(i).invoke(entity);
                //设置到PreparedStatement
                stmt.setObject(count , value);
                count++;
            }
        }
        //执行sql语句
        int rowsAffected= stmt.executeUpdate();
        //统一资源关闭
        JDBCUtil.closeConnection();
        JDBCUtil.closePreparedStatement();
        JDBCUtil.closeResultSet();
        // 返回插入是否成功
        return rowsAffected > 0;
    }
    //根据id修改实体  update student set stuName=?,stuSex=? where stuId=?
    @Override
    public boolean update(T entity) throws SQLException, InvocationTargetException, IllegalAccessException {
        String pojoName = myClass.getSimpleName(); // 获取纯类名，而不是全路径名
        String tableName = pojoName.toLowerCase();//类名全部小写是表名
        StringBuilder sb=new StringBuilder();
        sb.append(" update ").append(tableName).append(" set ");
        //获取所有的getXXX方法
        List<Method> getMethods = getAllGetXXX();
        for(int i=0;i<getMethods.size();i++){
            //根据方法名获取字段名
            String filedName=getFieldByMethodName(getMethods.get(i).getName());
            //判断字段名是否以Id结尾
            if(filedName.endsWith("Id")){
                continue;
            }else{
                sb.append(filedName).append("=").append("?").append(",");
            }
        }
        //将最后一个字符，删除掉
        sb.setCharAt(sb.length()-1,' ');
        sb.append(" where ").append(getPrimaryName()).append("=").append("?");
        String sql=sb.toString();
        //获取连接对象
        Connection connection = JDBCUtil.getConnection();
        //获取sql对象
        PreparedStatement stmt= JDBCUtil.getStatement(connection, sql);
        List<Method> methods = getAllGetXXX();
        Object primaryValue=null;
        int count=1;
        for(int i=0;i<methods.size();i++){
            //根据方法名获取字段名
            String filedName=getFieldByMethodName(methods.get(i).getName());
            //判断字段名是否以Id结尾
            if(filedName.endsWith("Id")){
                //调用方法获取值
                primaryValue=methods.get(i).invoke(entity);
                continue;
            }else{
                //获取方法
                Method method = methods.get(i);
                //获取方法的值
                Object value = method.invoke(entity);
                //设置到PreparedStatement
                stmt.setObject(count, value);
                count++;
            }
        }
        stmt.setObject(count, primaryValue);
        // 执行更新操作
        int  rowsAffected = stmt.executeUpdate();
        //关闭资源
        JDBCUtil.closeConnection();
        JDBCUtil.closePreparedStatement();
        JDBCUtil.closeResultSet();
        // 返回更新是否成功
        return rowsAffected > 0;
    }
    //根据id删除实体
    @Override
    public boolean deleteById(Integer id) throws SQLException {
        String pojoName = myClass.getSimpleName(); // 获取纯类名，而不是全路径名
        String tableName = pojoName.toLowerCase();//类名全部小写是表名
        //获取主键字段
        String primaryName = getPrimaryName();
        //编写sql语句
        String sql = "delete from "+ tableName+ " where "+primaryName+" = ?";
        //获取连接对象
        Connection connection = JDBCUtil.getConnection();
        //获取sql对象
        PreparedStatement stmt= JDBCUtil.getStatement(connection, sql);
        //设置参数
        stmt.setInt(1,id);
        int rows = stmt.executeUpdate();
        //统一资源关闭
        JDBCUtil.closeConnection();
        JDBCUtil.closePreparedStatement();
        JDBCUtil.closeResultSet();
        return rows>0? true:false;
    }
    //根据id查询实体  delete from student where stuId=?
    @Override
    public T getById(Integer id) throws SQLException, InvocationTargetException, InstantiationException, IllegalAccessException {
        String pojoName = myClass.getSimpleName(); // 获取纯类名  Student
        String tableName = pojoName.toLowerCase();//类名全部小写是表名  student
        //获取主键名称
        String primaryName=getPrimaryName();
        //编写sql语句
        String sql = "select * from "+ tableName+ " where " +primaryName+" = "+" ? ";
        //获取连接对象
        Connection connection = JDBCUtil.getConnection();
        //获取sql对象
        PreparedStatement stmt= JDBCUtil.getStatement(connection, sql);
        stmt.setInt(1,id);
        //获取结果集
        ResultSet resultSet = JDBCUtil.getResultSet(stmt);
        //遍历返回结果
        T t = commonGetAll(resultSet).get(0);
        //统一关闭资源
        JDBCUtil.closeConnection();
        JDBCUtil.closePreparedStatement();
        JDBCUtil.closeResultSet();
        //遍历结果集
        return t;
    }
    //查询所有
    @Override
    public List<T> getAll() throws SQLException, InvocationTargetException, InstantiationException, IllegalAccessException {
        String pojoName = myClass.getSimpleName(); // 获取纯类名  Student
        String tableName = pojoName.toLowerCase();//类名全部小写是表名  student
        //编写sql语句
        String sql = "select * from " + tableName;
        //获取连接对象
        Connection connection = JDBCUtil.getConnection();
        //获取sql对象
        PreparedStatement stmt= JDBCUtil.getStatement(connection, sql);
        //获取结果集
        ResultSet resultSet = JDBCUtil.getResultSet(stmt);
        List<T> list = commonGetAll(resultSet);
        //统一关闭资源
        JDBCUtil.closeConnection();
        JDBCUtil.closePreparedStatement();
        JDBCUtil.closeResultSet();
        return list;
    }
    //根据实体多条件查询
    @Override
    public List<T> getByCondition(T Entity) throws InvocationTargetException, IllegalAccessException, SQLException, InstantiationException {
        String pojoName = myClass.getSimpleName(); // 获取纯类名，而不是全路径名
        String tableName = pojoName.toLowerCase();//类名全部小写是表名
        StringBuilder sb = new StringBuilder();
        sb.append("select * from ").append(tableName).append(" where ");
        //判断实体的哪些字段设置了值
        List<Object> list=new ArrayList<>();
        //获取所有getXXX方法
        List<Method> methods = getAllGetXXX();
        for (Method method : methods) {
            Object value = method.invoke(Entity);
            if(value!=null){
                //字段的值加入集合中
                list.add(value);
                //字段设置了值(获取字段名拼接到sb中）
                sb.append(getFieldByMethodName(method.getName())).append(" = ").append(" ? ").append(" and ");
            }
        }
        //将最后一个and删除掉
        sb.replace(sb.length()-5,sb.length(),"");
        //编写sql语句
        String sql = sb.toString();
        //获取连接对象
        Connection connection = JDBCUtil.getConnection();
        //获取sql对象
        PreparedStatement stmt= JDBCUtil.getStatement(connection, sql);
        //设置参数
        for(int i=0;i<list.size();i++){
            stmt.setObject(i+1,list.get(i));
        }
        //获取结果集
        ResultSet resultSet = JDBCUtil.getResultSet(stmt);
        //遍历结果封装数据
        List<T> res = commonGetAll(resultSet);
        //统一关闭资源
        JDBCUtil.closeConnection();
        JDBCUtil.closePreparedStatement();
        JDBCUtil.closeResultSet();
        return res;
    }

    //利用反射获取所有的setXXX方法
    public List<Method> getAllSetXXX(){
        // 获取所有公共方法
        Method[] methods = myClass.getDeclaredMethods();
        List<Method> setterMethods=new ArrayList<>();
        // 过滤出所有setter方法
        for (Method method : methods) {
            if (method.getName().startsWith("set") && Modifier.isPublic(method.getModifiers())) {
                setterMethods.add(method);
            }
        }
        return setterMethods;
    }
    //利用反射获取所有的getXXX方法,排除getClass()方法
    public List<Method> getAllGetXXX(){
        // 获取所有公共方法
        Method[] methods = myClass.getDeclaredMethods();
        // 过滤出所有getter方法，排除getClass()方法
        List<Method> getterMethods=new ArrayList<>();
        for (Method method : methods) {
            if (method.getName().startsWith("get") && Modifier.isPublic(method.getModifiers()) && !method.getName().equals("getClass")) {
                getterMethods.add(method);
            }
        }
        return getterMethods;
    }
    //获取主键名称
    public String getPrimaryName(){
        //获取所有getXXX方法
        List<Method>  getterMethods= getAllGetXXX();
        for (Method getterMethod : getterMethods) {
            if(getterMethod.getName().endsWith("Id")){
                return getFieldByMethodName(getterMethod.getName());
            }
        }
        return null;
    }
    //根据指定的方法名称获取字段名称（setXXX,getXXX)
    public String getFieldByMethodName(String methodName){
        String xxxId=methodName.substring(3);
        char firstChar = Character.toLowerCase(xxxId.charAt(0));
        String res= firstChar + xxxId.substring(1);
        return res;
    }
    //获取所有的字段名称
    public List<String> getAllFiledName(){
        List<String> res=new ArrayList<>();
        //获取所有getXXX方法
        List<Method> methods = getAllGetXXX();
        for (Method method : methods) {
            res.add(getFieldByMethodName(method.getName()));
        }
        return res;
    }
    //根据传入的结果集进行遍历封装
    public List<T> commonGetAll(ResultSet resultSet) throws SQLException, InstantiationException, IllegalAccessException, InvocationTargetException {
        List<T> results = new ArrayList<T>();
        //获取setXXX方法
        List<Method> setterMethods = getAllSetXXX();
        // 处理结果集
        while (resultSet.next()) {
            T instance = myClass.newInstance();//获取实体对象
            for (int i = 1; i <= resultSet.getMetaData().getColumnCount(); i++) {
                // 获取列的名称和类型
                String columnName = resultSet.getMetaData().getColumnName(i);
                for (Method setterMethod : setterMethods) {
                    //根据传入的方法名称获取字段名称
                    String fieldName = getFieldByMethodName(setterMethod.getName());
                    if (fieldName.equals(columnName)) {
                        //调用方法设置值
                        setterMethod.invoke(instance, resultSet.getObject(columnName));
                        break;
                    }

                }
            }
            results.add(instance);
        }

        return results;
    }

}
